package com.project.application.server.system.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponseBody;
import com.aliyun.teaopenapi.models.Config;
import com.project.application.common.constant.Constants;
import com.project.application.common.exception.ServiceException;
import com.project.application.common.utils.VerifyCodeUtils;
import com.project.application.framework.redis.RedisCache;
import com.project.application.framework.web.domain.AjaxResult;
import com.project.application.server.system.service.CaptchaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author :levnli
 */
@Service
@Slf4j
public class CaptchaServiceImpl implements CaptchaService {

    @Autowired
    private RedisCache redisCache;

    @Value("${spring.profiles.active}")
    private String active;

    @Value("${sms.accessKeyId}")
    private String accessKeyId;

    @Value("${sms.accessKeySecret}")
    private String accessKeySecret;

    @Value("${sms.templateCode}")
    private String templateCode;

    @Value("${sms.signName}")
    private String signName;

    /**
     * 获取验证码
     * @return 验证码base64 图片
     */
    @Override
    public AjaxResult getCaptcha() {
        // 生成随机字串
        String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
        // 唯一标识
        String uuid = UUID.randomUUID().toString();
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;

        redisCache.setCacheObject(verifyKey, verifyCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        // 生成图片
        int w = 111, h = 36;

        try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
            VerifyCodeUtils.outputImage(w, h, stream, verifyCode);
            AjaxResult ajax = new AjaxResult();
            ajax.put("verifyKey", uuid);
            if (Constants.ACTIVE_DEV.equals(active)) {
                ajax.put("verifyCode", verifyCode);
            }
            ajax.put("img", "data:image/png;base64," + Base64.getEncoder().encodeToString(stream.toByteArray()));
            return ajax;
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 比对验证码
     * @param code 输入的验证码
     * @param uuid 验证码标示id
     */
    @Override
    public void validateCaptcha(String code, String uuid) {
        if (Constants.ACTIVE_DEV.equals(active)) {
            return;
        }
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null) {
            throw new ServiceException("验证码失效");
        }
        if (!code.equalsIgnoreCase(captcha)) {
            throw new ServiceException("验证码错误");
        }
    }

    /**
     * 获取验证码
     *
     * @param phone 手机号
     * @return 发送结果
     */
    @Override
    public boolean getSmsCaptcha(String phone) {
        if (!ReUtil.isMatch(Constants.PHONE_REGEX, phone)) {
            throw new ServiceException("手机号格式错误");
        }
        String smsCode = redisCache.getCacheObject(Constants.SMS_CODE_KEY + phone);
        if (StrUtil.isNotBlank(smsCode)) {
            throw new ServiceException("验证码未过期");
        }
        smsCode = String.valueOf(RandomUtil.randomInt(100000, 999999));

        Config config = new Config()
            // 您的 AccessKey ID
            .setAccessKeyId(accessKeyId)
            // 您的 AccessKey Secret
            .setAccessKeySecret(accessKeySecret);
        // 访问的域名
        config.endpoint = "dysmsapi.aliyuncs.com";

        Client client;
        try {
            client = new Client(config);
        } catch (Exception e) {
            throw new ServiceException("验证码配置错误");
        }
        Map<String, String> param = new HashMap<>(1);
        param.put("code", smsCode);
        SendSmsRequest sendSmsRequest = new SendSmsRequest();
        sendSmsRequest.setPhoneNumbers(phone);
        sendSmsRequest.setSignName(signName);
        sendSmsRequest.setTemplateCode(templateCode);
        sendSmsRequest.setTemplateParam(JSONUtil.toJsonStr(param));

        try {
            SendSmsResponseBody body = client.sendSms(sendSmsRequest).getBody();
            if (Constants.OK.equals(body.getCode())) {
                redisCache.setCacheObject(Constants.SMS_CODE_KEY + phone, smsCode, 15, TimeUnit.MINUTES);
                return true;
            } else {
                log.error(body.toString());
            }
        } catch (Exception e) {
            throw new ServiceException(e.getMessage());
        }
        throw new ServiceException("验证码发送失败");
    }

    /**
     * 比对验证码
     *
     * @param phone 手机号
     * @param code  验证码
     */
    @Override
    public void validateSmsCaptcha(String phone, String code) {
        if (Constants.ACTIVE_DEV.equals(active)) {
            return;
        }
        if (!ReUtil.isMatch(Constants.PHONE_REGEX, phone)) {
            throw new ServiceException("手机号格式错误");
        }
        if (StrUtil.isBlank(code)) {
            throw new ServiceException("请输入验证码");
        }
        String smsCode = redisCache.getCacheObject(Constants.SMS_CODE_KEY + phone);
        if (StrUtil.isBlank(smsCode)) {
            throw new ServiceException("验证码不存在");
        }
        if (!code.equals(smsCode)) {
            throw new ServiceException("验证码错误");
        }
        redisCache.deleteObject(Constants.SMS_CODE_KEY + phone);
    }
}
